/**
 * @author Vitor Franco do Carmo (vitor.carmo@capgemini.com)
 * @since 08/07/2013
 *
 */
package br.com.vfcfw.business.service;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.faces.model.DataModel;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;

import br.com.vfcfw.commons.domain.entity.BaseEntity;
import br.com.vfcfw.commons.domain.filter.BaseFilter;
import br.com.vfcfw.commons.exception.BusinessException;
import br.com.vfcfw.commons.util.SQLText;

/**
 * Interface base para todas as classes de negócio.
 * 
 * @author Vitor Franco do Carmo (vitor.carmo@capgemini.com)
 * @since 08/07/2013
 * 
 */
public interface IBaseService<E extends BaseEntity> extends Serializable {

    /**
     * Consulta uma entidade pelo ID da tabela.
     * 
     * @param entity Entidade persistente.
     * @return Entidade mapeada com JPA que atende ao identificador.
     * @throws BusinessException
     */
    public E consultarPorId(E entity) throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco.
     * 
     * @param filter Implementação de {@link BaseFilter} com atributos de consulta.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorFiltro(BaseFilter<E> filter) throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco usando paginação.
     * 
     * @param filter Implementação de {@link BaseFilter} com atributos de consulta.
     * @param inicio Início da consulta.
     * @param qtdRegistros Quantidade máxima de registros que podem ser retornados.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorFiltro(BaseFilter<E> filter, Integer inicio, Integer qtdRegistros)
        throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco usando paginação através de Query Nativa.
     * 
     * @param sql {@link SQLText} Sentença SQL Nativa que vai filtrar a consulta.
     * @param inicio Início da consulta.
     * @param qtdRegistros Quantidade máxima de registros que podem ser retornados.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<Map<String, Object>> consultarPorFiltroNativo(SQLText sql, Map<String, Object> projecao,
        Integer inicio, Integer qtdRegistros) throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco usando paginação.
     * 
     * @param sql {@link SQLText} Sentença SQL que vai filtrar a consulta.
     * @param inicio Início da consulta.
     * @param qtdRegistros Quantidade máxima de registros que podem ser retornados.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorFiltro(SQLText sql, Integer inicio, Integer qtdRegistros) throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco.
     * 
     * @param filter Implementação de {@link BaseFilter} com os critérios de consulta.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorCriterio(BaseFilter<E> filter) throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco usando paginação.
     * 
     * @param filter Implementação de {@link BaseFilter} com os critérios de consulta.
     * @param inicio Início da consulta.
     * @param qtdRegistros Quantidade máxima de registros que podem ser retornados.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorCriterio(BaseFilter<E> filter, Integer inicio, Integer qtdRegistros)
        throws BusinessException;

    /**
     * Consulta uma entidade pelo filtro no banco usando paginação.
     * 
     * @param detachedCriteria {@link DetachedCriteria} Critérios de pesquisa.
     * @param inicio Início da consulta.
     * @param qtdRegistros Quantidade máxima de registros que podem ser retornados.
     * @return Lista de objetos da entidade mapeada com JPA que atendem ao filtro.
     * @throws BusinessException
     */
    public List<E> consultarPorCriterio(DetachedCriteria detachedCriteria, Integer inicio, Integer qtdRegistros)
        throws BusinessException;

    /**
     * Retorna a quantidade de registros que atendem ao filtro passado.
     * 
     * @param filter Implementação de {@link BaseFilter} com os critérios de consulta.
     * @param filtroPorCriteria <tt>TRUE</tt> o {@link DataModel} usará {@link Criteria} para realizar a pesquisa,
     *        <tt>FALSE</tt> usará {@link Query}.
     * @return Quantidade de registros.
     */
    public int obterQuantidadeRegistros(BaseFilter<E> filter, boolean filtroPorCriteria) throws BusinessException;

    /**
     * Persiste ou altera uma entidade mapeada com JPA. <p>Se a pk estiver especificada na entidade persistente, ela
     * será alterada. Caso contrário, será persistida.</p>
     * 
     * @param entity Entidade mapeada com JPA.
     * @return Entidade mapeada com JPA.
     * @throws BusinessException
     */
    public abstract E salvar(E entity) throws BusinessException;

    /**
     * Persiste uma entidade.
     * 
     * @param entity Entidade mapeada com JPA.
     * @return Entidade mapeada com JPA.
     * @throws BusinessException
     */
    public abstract E incluir(E entity) throws BusinessException;

    /**
     * Altera uma entidade.
     * 
     * @param entity Entidade mapeada com JPA.
     * @return Entidade mapeada com JPA.
     * @throws BusinessException
     */
    public abstract E alterar(E entity) throws BusinessException;

    /**
     * Exclui o registro de uma entidade.
     * 
     * @param entity Entidade mapeada com JPA.
     * @return Entidade mapeada com JPA.
     * @throws BusinessException
     */
    public abstract void excluir(E entity) throws BusinessException;

}
